/* 
 *  Copyright (C) 2009-2010 milkyjing <milkyjing@gmail.com>
 *
 *  This Program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *   
 *  This Program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *  http://www.gnu.org/copyleft/gpl.html
 *
 */

#include "file.h"
#include "..\..\..\..\libtcs project\libtcs\trunk\tcs.c"


static void _tcxlib_sz_unicode_to_utf8(const wchar_t *uni, char **utf8, int *pSize) {
    int size;
    char *sz;
    size = WideCharToMultiByte(CP_UTF8, 0, uni, -1, NULL, 0, NULL, NULL);
    sz = (char *)malloc(size * sizeof(char));
    WideCharToMultiByte(CP_UTF8, 0, uni, -1, sz, size, NULL, NULL);
    *utf8 = sz;
    *pSize = size - 1;
}

TCX_PyAssFile tcxlib_create_ass_file(PyObject *self, PyObject *args) {
    PyObject *pyArg1, *pyArg2;
    unsigned char BOM[3];
    const wchar_t *filename;
    const wchar_t *header;
    int size;
    char *utf8;
    TCX_pAssFile pAssFile;
    TCX_PyAssFile pyAssFile;
    if (PyTuple_GET_SIZE(args) < 2) {
        PyErr_SetString(PyExc_RuntimeError, "CreateAssFile error, too less parameters - `(ass_file, ass_header)'\n");
        return NULL;
    }
    pyArg1 = PyTuple_GET_ITEM(args, 0);
    if (!PyUnicode_Check(pyArg1)) {
        PyErr_SetString(PyExc_RuntimeError, "CreateAssFile error, the 1st param should be a unicode string - `ass_file'\n");
        return NULL;
    }
    pyArg2 = PyTuple_GET_ITEM(args, 1);
    if (!PyUnicode_Check(pyArg2)) {
        PyErr_SetString(PyExc_RuntimeError, "CreateAssFile error, the 2nd param should be a unicode string - `ass_header'\n");
        return NULL;
    }
    filename = (const wchar_t *)PyUnicode_AsUnicode(pyArg1);
    header = (const wchar_t *)PyUnicode_AsUnicode(pyArg2);
    pAssFile = (TCX_pAssFile)malloc(sizeof(TCX_AssFile));
    pAssFile->fp = _wfopen(filename, L"wb");
    if (!pAssFile->fp) {
        free(pAssFile);
        PyErr_SetString(PyExc_RuntimeError, "CreateAssFile error, failed to create the file!\n");
        return NULL;
    }
    BOM[0] = 0xEF;
    BOM[1] = 0xBB;
    BOM[2] = 0xBF;
    fwrite(BOM, sizeof(unsigned char), 3, pAssFile->fp);
    _tcxlib_sz_unicode_to_utf8(header, &utf8, &size);
    fwrite(utf8, sizeof(char), size, pAssFile->fp);
    free(utf8);
    pyAssFile = PyTuple_New(1);
    PyTuple_SET_ITEM(pyAssFile, 0, PyLong_FromUnsignedLong((unsigned long)pAssFile));
    return pyAssFile;
}

static void _tcxlib_convert_ass_list_to_string(PyObject *assList, wchar_t **pAssString, int *pCount) {
    int i, count, size, offset;
    wchar_t *assString;
    wchar_t **pAssLine;
    int     *assLineSize;
    count = PyList_GET_SIZE(assList);
    assLineSize = (int *)malloc(count * sizeof(int));
    pAssLine = (wchar_t **)malloc(count * sizeof(wchar_t *));
    size = 0;
    for (i = 0; i < count; i ++) {
        pAssLine[i] = (wchar_t *)PyUnicode_AsUnicode(PyList_GET_ITEM(assList, i));
        assLineSize[i] = wcslen(pAssLine[i]);
        size += assLineSize[i];
    }
    assString = (wchar_t *)malloc((size + 1) * sizeof(wchar_t));
    offset = 0;
    for (i = 0; i < count; i ++) {
        memcpy(assString + offset, pAssLine[i], assLineSize[i] * sizeof(wchar_t));
        offset += assLineSize[i];
    }
    assString[size] = L'\0';
    free(pAssLine);
    free(assLineSize);
    *pAssString = assString;
    *pCount = size;
}

TCX_Py_Error_Code tcxlib_write_ass_file(PyObject *self, PyObject *args) {
    PyObject *pyArg1, *pyArg2;
    TCX_pAssFile pAssFile;
    TCX_PyAssFile pyAssFile;
    PyObject *assList;
    wchar_t *assString;
    char *utf8;
    int size;
    if (PyTuple_GET_SIZE(args) < 2) {
        PyErr_SetString(PyExc_RuntimeError, "WriteAssFile error, too less parameters - `(pyAssFile, ASS_BUF)'\n");
        return NULL;
    }
    pyArg1 = PyTuple_GET_ITEM(args, 0);
    if (!PyTuple_Check(pyArg1)) {
        PyErr_SetString(PyExc_RuntimeError, "WriteAssFile error, the 1st param should be a tuple - `pyAssFile'\n");
        return NULL;
    }
    pyArg2 = PyTuple_GET_ITEM(args, 1);
    if (!PyList_Check(pyArg2)) {
        PyErr_SetString(PyExc_RuntimeError, "WriteAssFile error, the 2nd param should be a list - `ASS_BUF'\n");
        return NULL;
    }
    pyAssFile = (TCX_PyAssFile)pyArg1;
    assList = pyArg2;
    pAssFile = (TCX_pAssFile)PyLong_AsUnsignedLong(PyTuple_GET_ITEM(pyAssFile, 0));
    _tcxlib_convert_ass_list_to_string(assList, &assString, &size);
    _tcxlib_sz_unicode_to_utf8(assString, &utf8, &size);
    free(assString);
    fwrite(utf8, sizeof(char), size, pAssFile->fp);
    free(utf8);
    return Py_BuildValue("i", 0);
}

TCX_Py_Error_Code tcxlib_fin_ass_file(PyObject *self, PyObject *args) {
    PyObject *pyArg1;
    TCX_pAssFile pAssFile;
    TCX_PyAssFile pyAssFile;
    if (PyTuple_GET_SIZE(args) < 1) {
        PyErr_SetString(PyExc_RuntimeError, "FinAssFile error, too less parameters - `(pyAssFile)'\n");
        return NULL;
    }
    pyArg1 = PyTuple_GET_ITEM(args, 0);
    if (!PyTuple_Check(pyArg1)) {
        PyErr_SetString(PyExc_RuntimeError, "FinAssFile error, the 1st param should be a tuple - `pyAssFile'\n");
        return NULL;
    }
    pyAssFile = (TCX_PyAssFile)pyArg1;
    pAssFile = (TCX_pAssFile)PyLong_AsUnsignedLong(PyTuple_GET_ITEM(pyAssFile, 0));
    fclose(pAssFile->fp);
    free(pAssFile);
    Py_CLEAR(pyAssFile);
    return Py_BuildValue("i", 0);
}

static void _tcxlib_get_numerator_and_denominator(double fps, unsigned long *pNumerator, unsigned long *pDenominator) {
    unsigned long numerator, denominator, x, y, t;
    denominator = 100000;
    numerator   = (unsigned long)(fps * denominator);
    x = numerator;
    y = denominator;
    while (y) {   // find gcd
        t = x % y;
        x = y;
        y = t;
    }
    numerator /= x;
    denominator /= x;
    *pNumerator = numerator;
    *pDenominator = denominator;
}

TCX_PyTcsFile tcxlib_create_tcs_file(PyObject *self, PyObject *args) {
    PyObject *pyArg1, *pyArg2, *pyArg3, *pyArg4;
    const wchar_t *filename;
    int fx_width;
    int fx_height;
    double fx_fps;
    TCX_pTcsFile pTcsFile;
    TCX_PyTcsFile pyTcsFile;
    if (PyTuple_GET_SIZE(args) < 4) {
        PyErr_SetString(PyExc_RuntimeError, "CreateTcsFile error, too less parameters - `(tcs_file, fx_width, fx_height, fx_fps)'\n");
        return NULL;
    }
    pyArg1 = PyTuple_GET_ITEM(args, 0);
    if (!PyUnicode_Check(pyArg1)) {
        PyErr_SetString(PyExc_RuntimeError, "CreateTcsFile error, the 1st param should be a unicode string - `tcs_file'\n");
        return NULL;
    }
    pyArg2 = PyTuple_GET_ITEM(args, 1);
    if (!PyLong_Check(pyArg2) && !PyFloat_Check(pyArg2)) {
        PyErr_SetString(PyExc_RuntimeError, "CreateTcsFile error, the 2nd param should be an integer - `fx_width'\n");
        return NULL;
    }
    pyArg3 = PyTuple_GET_ITEM(args, 2);
    if (!PyLong_Check(pyArg3) && !PyFloat_Check(pyArg3)) {
        PyErr_SetString(PyExc_RuntimeError, "CreateTcsFile error, the 3rd param should be an integer - `fx_height'\n");
        return NULL;
    }
    pyArg4 = PyTuple_GET_ITEM(args, 3);
    if (!PyLong_Check(pyArg4) && !PyFloat_Check(pyArg4)) {
        PyErr_SetString(PyExc_RuntimeError, "CreateTcsFile error, the 4th param should be a float - `fx_fps'\n");
        return NULL;
    }
    filename = (const wchar_t *)PyUnicode_AsUnicode(pyArg1);
    fx_width = (int)PyLong_AsLong(pyArg2);
    fx_height = (int)PyLong_AsLong(pyArg3);
    fx_fps = (double)PyFloat_AsDouble(pyArg4);
    pTcsFile = (TCX_pTcsFile)malloc(sizeof(TCX_TcsFile));
    if (libtcs_open_file_w(&pTcsFile->file, filename, tcs_file_create_new) != tcs_error_success) {
        free(pTcsFile);
        PyErr_SetString(PyExc_RuntimeError, "CreateTcsFile error, failed to create the file!\n");
        return NULL;
    }
    _tcxlib_get_numerator_and_denominator(fx_fps, &pTcsFile->header.fpsNumerator, &pTcsFile->header.fpsDenominator);
    libtcs_set_header(&pTcsFile->header, TCS_FLAG_COMPRESSED, fx_width, fx_height, TCS_INIT_MIN_TIME, TCS_INIT_MAX_TIME, 0, pTcsFile->header.fpsNumerator, pTcsFile->header.fpsDenominator);
    libtcs_set_file_position_indicator(&pTcsFile->file, tcs_fpi_header);
    pyTcsFile = PyTuple_New(1);
    PyTuple_SET_ITEM(pyTcsFile, 0, PyLong_FromUnsignedLong((unsigned long)pTcsFile));
    return pyTcsFile;
}

static void _tcxlib_convert_tcs_list_to_buf(PyObject *tcsList, unsigned long **pTcsBuf, unsigned long *pCount) {
    int i, count;
    PyObject *pyTcsItem;
    unsigned short x, y;
    unsigned long RGB;
    unsigned char alpha;
    unsigned long *tcsBuf;
    count = PyList_GET_SIZE(tcsList);
    /* tcs buffer from user tcx py script: (Start, End, Layer, PosX, PosY, RGB, Alpha) */
    /* a raw tcs chunk defined in TCC file format specification: (Start, End, Layer, Pos, RGBA) */
    tcsBuf = (unsigned long *)malloc(count * 5 * sizeof(unsigned long));
    for (i = 0; i < count; i ++) {
        pyTcsItem = PyList_GET_ITEM(tcsList, i);
        x = (unsigned short)PyLong_AsLong(PyTuple_GET_ITEM(pyTcsItem, 3));
        y = (unsigned short)PyLong_AsLong(PyTuple_GET_ITEM(pyTcsItem, 4));
        RGB = (unsigned long)PyLong_AsLong(PyTuple_GET_ITEM(pyTcsItem, 5));
        alpha = (unsigned char)PyLong_AsLong(PyTuple_GET_ITEM(pyTcsItem, 6));
        tcsBuf[5 * i + 0] = PyLong_AsLong(PyTuple_GET_ITEM(pyTcsItem, 0));    /* Start */
        tcsBuf[5 * i + 1] = PyLong_AsLong(PyTuple_GET_ITEM(pyTcsItem, 1));    /* End */
        tcsBuf[5 * i + 2] = PyLong_AsLong(PyTuple_GET_ITEM(pyTcsItem, 2));    /* Layer */
        tcsBuf[5 * i + 3] = (x | ((unsigned long)y << 16));
        tcsBuf[5 * i + 4] = (RGB | ((unsigned long)alpha << 24));
    }
    *pTcsBuf = tcsBuf;
    *pCount = count;
}

TCX_Py_Error_Code tcxlib_write_tcs_file(PyObject *self, PyObject *args) {
    PyObject *pyArg1, *pyArg2;
    TCX_pTcsFile pTcsFile;
    TCX_PyTcsFile pyTcsFile;
    PyObject *tcsList;
    tcs_unit *tcsBuf;
    tcs_unit *compTcsBuf;
    tcs_u32 count, chunks, units;
    if (PyTuple_GET_SIZE(args) < 2) {
        PyErr_SetString(PyExc_RuntimeError, "WriteTcsFile error, too less parameters - `(pyTcsFile, TCS_BUF)'\n");
        return NULL;
    }
    pyArg1 = PyTuple_GET_ITEM(args, 0);
    if (!PyTuple_Check(pyArg1)) {
        PyErr_SetString(PyExc_RuntimeError, "WriteTcsFile error, the 1st param should be a tuple - `pyTcsFile'\n");
        return NULL;
    }
    pyArg2 = PyTuple_GET_ITEM(args, 1);
    if (!PyList_Check(pyArg2)) {
        PyErr_SetString(PyExc_RuntimeError, "WriteTcsFile error, the 2nd param should be a list - `TCS_BUF'\n");
        return NULL;
    }
    pyTcsFile = (TCX_PyTcsFile)pyArg1;
    tcsList = pyArg2;
    pTcsFile = (TCX_pTcsFile)PyLong_AsUnsignedLong(PyTuple_GET_ITEM(pyTcsFile, 0));
    _tcxlib_convert_tcs_list_to_buf(tcsList, &tcsBuf, &count);
    libtcs_get_raw_chunks_min_max_time((const TCS_pRawChunk)tcsBuf, count, &pTcsFile->header);
    libtcs_compress_raw_chunks((const TCS_pRawChunk)tcsBuf, count, &compTcsBuf, &chunks, &units);
    free(tcsBuf);
    pTcsFile->header.chunks += chunks;
    libtcs_write(&pTcsFile->file, compTcsBuf, units);
    free(compTcsBuf);
    return Py_BuildValue("i", 0);
}

TCX_Py_Error_Code tcxlib_fin_tcs_file(PyObject *self, PyObject *args) {
    PyObject *pyArg1;
    TCX_pTcsFile pTcsFile;
    TCX_PyTcsFile pyTcsFile;
    if (PyTuple_GET_SIZE(args) < 1) {
        PyErr_SetString(PyExc_RuntimeError, "FinTcsFile error, too less parameters - `(pyTcsFile)'\n");
        return NULL;
    }
    pyArg1 = PyTuple_GET_ITEM(args, 0);
    if (!PyTuple_Check(pyArg1)) {
        PyErr_SetString(PyExc_RuntimeError, "FinTcsFile error, the 1st param should be a tuple - `pyTcsFile'\n");
        return NULL;
    }
    pyTcsFile = (TCX_PyTcsFile)pyArg1;
    pTcsFile = (TCX_pTcsFile)PyLong_AsUnsignedLong(PyTuple_GET_ITEM(pyTcsFile, 0));
    libtcs_write_header(&pTcsFile->file, &pTcsFile->header, 0);
    libtcs_close_file(&pTcsFile->file);
    free(pTcsFile);
    Py_CLEAR(pyTcsFile);
    return Py_BuildValue("i", 0);
}

